<template>
  <div
    :style="{
      scale: scaleVal,
      left: `${position.left}px`,
      top: `${position.top}px`,
    }"
    class="draggable-content"
    ref="containerRef"
    @wheel.stop.prevent="handleWheel"
  >
    <slot></slot>
  </div>
</template>

<script setup>
import { onBeforeUnmount, onMounted, ref } from 'vue';

const props = defineProps({
  /**
   * 缩放步进值
   */
  scaleStep: {
    type: Number,
    default: 0.1,
  },
});
const containerRef = ref();
// 状态变量
const position = ref({
  left: 0,
  top: 0,
});

/**
 * 缩放
 */
const scaleVal = ref(1);

// 位置界限
const limitPostion = ref({
  maxLeft: 0,
  maxTop: 0,
});

onMounted(() => {
  const { offsetWidth, offsetHeight, parentElement } = containerRef.value;
  limitPostion.value = {
    maxLeft: parentElement.offsetWidth - offsetWidth,
    maxTop: parentElement.offsetHeight - offsetHeight,
  };
  position.value = {
    left: (parentElement.offsetWidth - offsetWidth) / 2,
    top: (parentElement.offsetHeight - offsetHeight) / 2,
  };
  parentElement.addEventListener('mousedown', startDrag);
  parentElement.addEventListener('mousemove', dragElement);
  parentElement.addEventListener('mouseup', endDrag);
});

onBeforeUnmount(() => {
  const { parentElement } = containerRef.value;
  parentElement.removeEventListener('mousedown', startDrag);
  parentElement.removeEventListener('mousemove', dragElement);
  parentElement.removeEventListener('mouseup', endDrag);
});

let offsetX = 0;
let offsetY = 0;
// 开始拖拽
const startDrag = (e) => {
  e.preventDefault();
  isDrag.value = true;
  offsetX = e.clientX - position.value.left;
  offsetY = e.clientY - position.value.top;
};

const isDrag = ref(false);

// 拖拽元素
// const dragElement = throttle((e) => {
//   if (!isDrag.value) {
//     return;
//   }
//   const left = e.clientX - offsetX;
//   //   x.value = ;
//   const top = e.clientY - offsetY;
//   position.value = {
//     top,
//     left,
//   };
// }, 100);

const dragElement = (e) => {
  if (!isDrag.value) {
    return;
  }
  const left = e.clientX - offsetX;
  //   x.value = ;
  const top = e.clientY - offsetY;
  position.value = {
    top,
    left,
  };
};

// 结束拖拽
const endDrag = (e) => {
  isDrag.value = false;
  const left = e.clientX - offsetX;
  //   x.value = ;
  const top = e.clientY - offsetY;
  position.value = {
    top,
    left,
  };
};

// 处理滚轮
const handleWheel = (e) => {
  let result = scaleVal.value;
  const { deltaY } = e;
  // 判断滚轮方向
  if (deltaY > 0) {
    // 向下滚动，缩小
    result -= props.scaleStep;
  } else if (deltaY < 0) {
    // 向上滚动，放大
    result += props.scaleStep;
  }
  result = Number(result.toFixed(1));
  if (result > 5 || result < 0.1) {
    return;
  }
  const { offsetHeight, offsetWidth, parentElement } = containerRef.value;
  if (
    result * offsetHeight > parentElement.offsetHeight ||
    result * offsetWidth > parentElement.offsetWidth
  ) {
    return;
  }

  scaleVal.value = result;
};

/**
 * 向上居中
 */
const handleAlignTop = () => {
  const { parentElement, offsetWidth, offsetHeight } = containerRef.value;
  let positionScale = Number((scaleVal.value - 1).toFixed(1));

  let result = {
    top: (offsetHeight * positionScale) / 2,
    left: (parentElement.offsetWidth - offsetWidth) / 2,
  };

  position.value = result;
};
/**
 * 向下居中
 */
const handleAlignBottom = () => {
  const { parentElement, offsetWidth, offsetHeight } = containerRef.value;
  let positionScale = scaleVal.value - 1;
  let result = {
    top:
      parentElement.offsetHeight -
      offsetHeight -
      (offsetHeight * positionScale) / 2,
    left: (parentElement.offsetWidth - offsetWidth) / 2,
  };

  position.value = result;
};

/**
 * 完全居中
 */
const handleAllAlignCenter = () => {
  scaleVal.value = 1;
  const { parentElement, offsetWidth, offsetHeight } = containerRef.value;
  let result = {
    top: (parentElement.offsetHeight - offsetHeight) / 2,
    left: (parentElement.offsetWidth - offsetWidth) / 2,
  };

  position.value = result;
};

/**
 * 放大
 */
const handleMagnify = () => {
  let result = scaleVal.value + props.scaleStep;
  const { offsetHeight, offsetWidth, parentElement } = containerRef.value;
  if (
    result * offsetHeight > parentElement.offsetHeight ||
    result * offsetWidth > parentElement.offsetWidth
  ) {
    return;
  }
  scaleVal.value = result;
};

/**
 * 缩小
 */
const handleLessen = () => {
  let result = scaleVal.value - props.scaleStep;
  if (result < 0.1) {
    return;
  }
  scaleVal.value = result;
};

defineExpose({
  handleAlignTop,
  handleAlignBottom,
  handleAllAlignCenter,
  handleMagnify,
  handleLessen,
});
</script>

<style scoped>
.draggable-content {
  position: absolute;
  overflow: hidden;
  transition: all 0.1s;
}
</style>
